package com.kgcx.schedule.service;

import com.kgcx.common.client.organization.pojo.Driver;
import com.kgcx.common.constant.Cons;
import com.kgcx.core.exception.BusinessException;
import com.kgcx.core.utils.HelpUtil;
import com.kgcx.schedule.client.Airport;
import com.kgcx.schedule.domain.ScheduleRecordDomain;
import com.kgcx.schedule.model.ScheduleRound;
import com.kgcx.schedule.model.SpeciallyBook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.util.*;

/**
 * 预约接机
 *
 * @author 袁进勇
 */
@Service
public class SchedulePlanPlanePickOrderService extends ScheduleOrderBookService {
    private static final Logger LOG = LoggerFactory.getLogger(SchedulePlanPlanePickOrderService.class);

    private SpeciallyBook setting = null;

    @Override
    protected Timestamp calculateScheduleTime(ScheduleRecordDomain record) {
        SpeciallyBook setting = getScheduleSetting(record.getCity_id());
        return HelpUtil.addTime(record.getPlan_depart_time(), Calendar.MINUTE, 0 - setting.getMin_time());
    }

    @Override
    protected Timestamp getMinTime(ScheduleRecordDomain record) {
        SpeciallyBook setting = getScheduleSetting(record.getCity_id());
        return HelpUtil.addTime(record.getCreate_time(), Calendar.MINUTE, setting.getMin_time());
    }

    @Override
    protected Timestamp getMaxTime(ScheduleRecordDomain record) {
        SpeciallyBook setting = getScheduleSetting(record.getCity_id());
        return HelpUtil.addTime(record.getCreate_time(), Calendar.DAY_OF_MONTH, setting.getMin_time());
    }

    /**
     * 按状态对司机进行分组
     *
     * @param driverList
     * @return
     */
    @Override
    protected Map<Integer, List<Driver>> groupingDrivers(ScheduleRecordDomain record, List<Driver> driverList) {
        Map<Integer, List<Driver>> driverMap = new HashMap<Integer, List<Driver>>();
        driverMap.put(Cons.DRIVER_STATE_ON, new ArrayList<Driver>()); // 上线
        driverMap.put(Cons.DRIVER_STATE_STAY, new ArrayList<Driver>()); // 待命
        driverMap.put(Cons.DRIVER_STATE_PREIN, new ArrayList<Driver>()); // 入栈中
        driverMap.put(Cons.DRIVER_STATE_IN, new ArrayList<Driver>()); // 入栈

        for (Driver driver : driverList) {
            if (!Cons.DRIVER_STATE_ON.equals(driver.getState())) {
                if (!driver.getAirportId().equals(record.getAirport_id())) {
                    LOG.debug(String.format("订单[%s]，忽略司机[%d]，司机当前机场ID为[%d]，与接机ID[%d]不匹配，！", record.getOrder_no(),
                            driver.getKid(), driver.getAirportId(), record.getAirport_id()));
                    continue;
                }
            }
            driverMap.get(driver.getState()).add(driver);
        }

        return driverMap;
    }

    @Override
    protected Driver chooseDriver(ScheduleRecordDomain record, Map<Integer, List<Driver>> driverMap) {
        LOG.info(String.format("订单[%s]，调度车辆/司机。", record.getOrder_no()));

        // 预约接机、接站的，用车时间小于可预约最短时间，可以下单成功，立即进行派单。
        if (record.getCreate_time().equals(record.getFisrt_schedule_time())) {
            return chooseDriver4Now(record, driverMap);
        } else {
            return chooseDriver4Book(record, driverMap);
        }
    }

    private Driver chooseDriver4Now(ScheduleRecordDomain record, Map<Integer, List<Driver>> driverMap) {
        // 1、有入栈车辆时，按入栈排队顺序调度
        Driver driver = chooseStateInDriver(record, driverMap);
        if (driver != null) {
            LOG.info(String.format("订单[%s]，找到符合调度规则的入栈车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                    driver.getAutoId(), driver.getKid()));
            return driver;
        }

        // 2、有入栈中车辆时，按入栈中状态变更顺序调度
        driver = chooseStatePreInDriver(record, driverMap);
        if (driver != null) {
            LOG.info(String.format("订单[%s]，找到符合调度规则的入栈中车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                    driver.getAutoId(), driver.getKid()));
            return driver;
        }

        // 3、有待命车辆时，按待命排队顺序调度
        SpeciallyBook setting = getScheduleSetting(record.getCity_id());
        if (Cons.$true(setting.getIs_standby())) {
            driver = chooseStateStayDriver(record, driverMap);
            if (driver != null) {
                LOG.info(String.format("订单[%s]，找到符合调度规则的待命车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                        driver.getAutoId(), driver.getKid()));
                return driver;
            }
        } else {
            LOG.info(String.format("订单[%s]，立即接机/站的调度参数“是否给待命车辆派车”开关未开启。", record.getOrder_no()));
        }

        // 4、场外在线车辆派单
        if (Cons.$true(setting.getIs_online())) {
            driver = chooseStateOnDriver(record, driverMap);
            if (driver != null) {
                LOG.info(String.format("订单[%s]，找到符合调度规则的场外在线车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                        driver.getAutoId(), driver.getKid()));
                return driver;
            }
        } else {
            LOG.info(String.format("订单[%s]，立即接机/站的调度参数“是否给场外车辆派车”开关未开启。", record.getOrder_no()));
        }

        return null;
    }

    private Driver chooseDriver4Book(ScheduleRecordDomain record, Map<Integer, List<Driver>> driverMap) {
        Driver driver = null;
        // 1、有待命车辆时，按待命排队顺序调度
        SpeciallyBook setting = getScheduleSetting(record.getCity_id());
        if (Cons.$true(setting.getIs_standby())) {
            driver = chooseStateStayDriver(record, driverMap);
            if (driver != null) {
                LOG.info(String.format("订单[%s]，找到符合调度规则的待命车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                        driver.getAutoId(), driver.getKid()));
                return driver;
            }
        } else {
            LOG.info(String.format("订单[%s]，立即接机/站的调度参数“是否给待命车辆派车”开关未开启。", record.getOrder_no()));
        }

        // 2、有入栈中车辆时，按入栈中状态变更顺序调度
        driver = chooseStatePreInDriver(record, driverMap);
        if (driver != null) {
            LOG.info(String.format("订单[%s]，找到符合调度规则的入栈中车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                    driver.getAutoId(), driver.getKid()));
            return driver;
        }

        // 3、有入栈车辆时，按入栈排队顺序调度
        driver = chooseStateInDriver(record, driverMap);
        if (driver != null) {
            LOG.info(String.format("订单[%s]，找到符合调度规则的入栈车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                    driver.getAutoId(), driver.getKid()));
            return driver;
        }

        // 4、场外在线车辆派单
        if (Cons.$true(setting.getIs_online())) {
            driver = chooseStateOnDriver(record, driverMap);
            if (driver != null) {
                LOG.info(String.format("订单[%s]，找到符合调度规则的场外在线车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                        driver.getAutoId(), driver.getKid()));
                return driver;
            }
        } else {
            LOG.info(String.format("订单[%s]，立即接机/站的调度参数“是否给场外车辆派车”开关未开启。", record.getOrder_no()));
        }

        return null;
    }

    @Override
    protected ScheduleRound getScheduleRound(ScheduleRecordDomain record) {
        SpeciallyBook setting = getScheduleSetting(record.getCity_id());
        if (Cons.$true(setting.getIs_online())) {
            List<ScheduleRound> rounds = null;
            // 预约接机、接站的，用车时间小于可预约最短时间，可以下单成功，立即进行派单。
            if (record.getCreate_time().equals(record.getFisrt_schedule_time())) {
                rounds = setting.getNowRounds();
            } else {
                rounds = setting.getBookRounds();
            }

            if (!HelpUtil.isEmpty(rounds) && rounds.size() > record.getSchedule_count()) {
                return rounds.get(record.getSchedule_count());
            }
        }

        return null;
    }

    @Override
    protected void scheduleSuccessful(ScheduleRecordDomain record, Driver driver) {
        // 更新推送司机信息给乘客的时间，改派司机后，需要设置推送时间和状态
        updateNotifyTime(record,
                HelpUtil.addTime(record.getPlan_depart_time(), Calendar.MINUTE, 0 - setting.getNotify_time()));

        // 短信通知下单人
        SpeciallyBook setting = getScheduleSetting(record.getCity_id());
        String placingUserPhone = record.getPlacing_user_phone();
        if (Cons.$true(setting.getIs_send_msg())) { // 短信发送开关打开
            sendSuccessfulMSG(placingUserPhone, setting.getMsg_id(), record);
        }

        // 给别人叫车时，检查是否短信通知乘车人
        String passengerPhone = record.getPassenger_phone();
        if (Cons.$true(record.getIs_msg_passenger())
                && (!HelpUtil.isEmpty(passengerPhone) && !passengerPhone.equals(placingUserPhone))) {
            sendSuccessfulMSG(passengerPhone, setting.getMsg_id(), record);
        }
    }

    private SpeciallyBook getScheduleSetting(Long cityId) {
        return scheduleSettingsService.getSetting(cityId, SpeciallyBook.class);
    }

    @Override
    protected String getAdminPhone(ScheduleRecordDomain record) {
        Airport airport = cityClient.getAirport(record.getAirport_id());
        if (airport != null) {
            return airport.getManagerPhone();
        }

        LOG.error(String.format("获取机场[%d]信息失败，机场不存在！", record.getAirport_id()));
        throw new BusinessException(1L, "获取机场[" + record.getAirport_id() + "]信息失败，机场不存在！");
    }
}
